import { Injectable } from '@angular/core';
import { Subject, Observable } from 'rxjs';

export type SortOrder = 'desc' | 'asc';

export type SortMode = 'single' | 'multiple';

export class SortItem {
  sortKey: string;
  sortOrder: SortOrder;
  timestamp: number;

  constructor(sortKey: string, sortOrder: SortOrder) {
    this.sortKey = sortKey;
    this.sortOrder = sortOrder;
  }

  nextOrder() {
    if (!this.sortOrder) {
      this.sortOrder = 'desc';
    } else if (this.sortOrder === 'desc') {
      this.sortOrder = 'asc';
    } else {
      this.sortOrder = null;
    }
  }
}

export class SortState {
  sortedBy: string;
  order: string;
}

@Injectable()
export class TableSortService {
  /** Sort config items. */
  sortItems: SortItem[] = [];

  /** Sort mode. Multiple sort can use multiple value to sort. */
  sortMode: 'single' | 'multiple' = 'single';

  /** Sort change subject. */
  sortChangeSubject = new Subject<SortState>();

  constructor() { }

  /** Set sort mode */
  setMode(mode: SortMode = 'single') {
    this.sortMode = mode;
  }

  /** Register sort config item. */
  registerSortItem(item: SortItem) {
    this.sortItems.push(item);
  }

  /** Unregister sort config item. */
  unregisterSortItem(sortKey: string) {
    const idx = this.sortItems.findIndex((item) => item.sortKey === sortKey);
    this.sortItems.splice(idx, 1);
  }

  /** Sort change for a sort key. */
  sortChange(sortKey: string) {
    const oldItem = this.sortItems.find((item) => item.sortKey === sortKey);
    if (this.sortMode === 'single') {
      this.sortItems.filter((item) => item.sortKey !== sortKey)
        .map((item) => item.sortOrder = null);
    }

    oldItem.timestamp = new Date().getTime();
    // 最近操作的排序项排在后面
    const items = this.sortItems.filter((item) => item.sortOrder).sort((a, b) => a.timestamp - b.timestamp);
    this.sortChangeSubject.next(this.format(items));
  }

  private format(sortItems: SortItem[]): SortState {
    return {
      sortedBy: sortItems.map((item) => item.sortKey).join(','),
      order: sortItems.map((item) => item.sortOrder).join(','),
    };
  }
}
